package com.caine.tc;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TestMain {

    private static DataMapping unWrap(ByteBuf buf) {
        DataMapping mapping = new DataMapping();
        // 需要满足最小数据包25 + 1才处理
        if (buf.readableBytes() < 25 + 1) {
            return null;
        }
        byte cmd = buf.getByte(2);// 命令标识
        byte an = buf.getByte(3);//应答标识
        byte[] vinBys = new byte[17];// vin
        buf.getBytes(4, vinBys);
        String vin = new String(vinBys, StandardCharsets.US_ASCII);
        byte en = buf.getByte(21);
        int dataLen = buf.getShort(22);
        byte[] cellData = new byte[dataLen];
        buf.getBytes(24, cellData);
        byte sourceBcc = buf.getByte(24 + dataLen);
        // 获取需要计算bcc的数据 从命令单元开始计算
        byte[] bccData = new byte[1 + 1 + 17 + 1 + 2 + dataLen];
        // 从下标2开始获取数据
        buf.getBytes(2, bccData);
        byte bcc = bcc(bccData);
        if (bcc != sourceBcc) {
            //bcc 校验不过数据有问题 不处理
            return null;
        }
        mapping.setType(cmd);
        mapping.setData(cellData);
        return mapping;
    }

    private static byte bcc(byte[] data) {
        byte bcc = 0x00;
        for (int i = 0; i < data.length; i++) {
            bcc = (byte) (bcc ^ data[i]);
        }
        return bcc;
    }

    private void analysis(ByteBuf buf, Map<String, Object> retMap) {
        try {
            byte b = buf.readByte();
            switch (b) {
                case 0x01://整车数据
                    Map<String, Object> map01 = vehicleInfo(buf);
                    if (map01 != null) {
                        retMap.put("0x01", map01);
                        analysis(buf, retMap);
                    }
                    break;
                case 0x02:// 驱动电机数据
                    Map<String, Object> map02 = driveInfo(buf);
                    if (map02 != null) {
                        retMap.put("0x02", map02);
                        analysis(buf, retMap);
                    }
                    break;
                case 0x03:// 燃料电池数据
                    Map<String, Object> map03 = fuelCellInfo(buf);
                    if (map03 != null) {
                        retMap.put("0x03", map03);
                        analysis(buf, retMap);
                    }
                    break;
                case 0x04:// 发动机数据
                    Map<String, Object> map04 = engineInfo(buf);
                    if (map04 != null) {
                        retMap.put("0x04", map04);
                        analysis(buf, retMap);
                    }
                    break;
                case 0x05:// 车辆位置数据
                    Map<String, Integer> map05 = positionInfo(buf);
                    if (map05 != null) {
                        retMap.put("0x05", map05);
                        analysis(buf, retMap);
                    }
                case 0x06:// 极值包不处理
                   // log here
                    System.out.println("极值数据不处理..............");

            }
        } catch (IndexOutOfBoundsException e) {

        }
    }

    // 0x01 整车数据
    private Map<String, Object> vehicleInfo(ByteBuf buf) {
        Map<String, Object> retMap = new HashMap<>();
        int status = buf.readByte() & 0xff;
        retMap.put("status", status);
        int charge = buf.readByte() & 0xff;
        retMap.put("charge", charge);
        int runMode = buf.readByte() & 0xff;
        retMap.put("runMode", runMode);
        int speed = buf.readShort();
        retMap.put("speed", speed);
        long mileage = buf.readInt();
        retMap.put("mileage", mileage);
        int voltage = buf.readShort();
        retMap.put("voltage", voltage);
        int current = buf.readShort();
        retMap.put("current", current);
        int soc = buf.readByte() & 0xff;
        retMap.put("soc", soc);
        int dcStatus = buf.readByte() & 0xff;
        retMap.put("dcStatus", dcStatus);
        int level = buf.readByte() & 0xff;
        retMap.put("level", level);
        int resistance = buf.readShort();
        retMap.put("resistance", resistance);
        int backup = buf.readShort();
        retMap.put("backup", backup);
        return retMap;
    }

    // 0x02 驱动电机数据
    private Map<String, Object> driveInfo(ByteBuf buf) {
        Map<String, Object> retMap = new HashMap<>();
        int driveCnt = buf.readByte() & 0xff;
        // 驱动电机个数需要循环
        for (int i = 0; i < driveCnt; i++) {
            Map<String, Object> map = new HashMap<>();
            //驱动电机序号
            int serNo = buf.readByte() & 0xff;
            map.put("serNo", serNo);
            //驱动电机状态
            int status = buf.readByte() & 0xff;
            map.put("status", status);
            //驱动电机控制器温度
            int controlTemp = buf.readByte() & 0xff;
            map.put("controlTemp", controlTemp);
            // 驱动电机转速
            int speed = buf.readShort();
            map.put("speed", speed);
            // 驱动电机转矩
            int round = buf.readShort();
            map.put("round", round);
            // 驱动电机温度
            int currentTemp = buf.readByte() & 0xff;
            map.put("currentTemp", currentTemp);
            // 电机控制器输入电压
            int voltage = buf.readShort();
            map.put("voltage", voltage);
            // 电机控制器直流母线电流
            int current = buf.readShort();
            map.put("current", current);
            retMap.put(String.valueOf(i), map);
        }
        return retMap;
    }

    // 0x03 燃料电池数据
    private Map<String, Object> fuelCellInfo(ByteBuf buf) {
        Map<String, Object> retMap = new HashMap<>();
        // 燃料电池电压
        int voltage = buf.readShort();
        retMap.put("voltage", voltage);
        // 燃料电池电流
        int current = buf.readShort();
        retMap.put("current", current);
        // 燃料消耗率
        int percent = buf.readShort();
        retMap.put("percent", percent);
        // 燃料电池温度探针总数
        int agentCnt = buf.readShort();
        retMap.put("agentCnt", agentCnt);
        // 探针温度列表
        List<Integer> tempLst = new ArrayList<>();
        for (int i = 0; i < agentCnt; i++) {
            int tmp = buf.readByte() & 0xff;
            tempLst.add(tmp);
        }
        retMap.put("tempLst", tempLst);
        // 氢系统中最高温度
        int maxTemp = buf.readShort();
        retMap.put("maxTemp", maxTemp);
        // 氢系统中最高温度探针代号
        int maxTempSerNo = buf.readByte() & 0xff;
        retMap.put("maxTempSerNo", maxTempSerNo);
        // 氢气最高浓度
        int maxConcentration = buf.readShort();
        retMap.put("maxConcentration", maxConcentration);
        // 氢气最高浓度传感器代号
        int maxConcentrationSerNo = buf.readByte() & 0xff;
        retMap.put("maxConcentrationSerNo", maxConcentrationSerNo);
        // 氢气最高压力
        int maxPressure = buf.readShort();
        retMap.put("maxPressure", maxPressure);
        // 氢气最高压力传感器代号
        int maxPressureSerNo = buf.readByte() & 0xff;
        retMap.put("maxPressureSerNo", maxPressureSerNo);
        // 高压 DC/DC状态
        int dcStatus = buf.readByte() & 0xff;
        retMap.put("dcStatus", dcStatus);
        return retMap;
    }

    // 0x04 发动机数据
    private Map<String, Object> engineInfo(ByteBuf buf) {
        Map<String, Object> retMap = new HashMap<>();
        // 发动机状态
        int status = buf.readByte() & 0xff;
        retMap.put("status", status);
        // 曲轴转速
        int speed = buf.readShort();
        retMap.put("speed", speed);
        // 燃料消耗率
        int precent = buf.readShort();
        retMap.put("precent", precent);
        return retMap;
    }

    // 0x05 车辆位置数据
    private Map<String, Integer> positionInfo(ByteBuf buf) {
        Map<String, Integer> retMap = new HashMap<>();
        int status = buf.readByte() & 0xff;
        retMap.put("status", status);
        // 经度
        int longitude = buf.readInt();
        retMap.put("longitude", longitude);
        // 纬度
        int latitude = buf.readInt();
        retMap.put("latitude", latitude);
        return retMap;
    }

    private static String getYMD(ByteBuf buf) {
        int year = (buf.readByte() & 0xff) + 2000;
        int month = buf.readByte() & 0xff;
        int day = buf.readByte() & 0xff;
        int hour = buf.readByte() & 0xff;
        int min = buf.readByte() & 0xff;
        int sec = buf.readByte() & 0xff;
        return year + "/" + month + "/" + day + " " + hour + ":" + min + ":" + sec;
    }

    // 输出解析的数据
    private static void printInfo(Map<String, Object> retMap){
        retMap.forEach((k,v)->{
           switch (k){
               case "0x01":
                   break;
               case "0x05":
                   Map<String, Integer> map = (Map<String, Integer>)v;
                   int status = map.get("status");
                   // 经度
                   double longitude =  map.get("longitude") / 1000000.00d;
                   // 纬度
                   double latitude = map.get("latitude") / 1000000.00d;
                   System.out.println("定位状态:"+status+" 经度:"+longitude+" 纬度:"+latitude);
           }
        });
    }

    public byte[] getData(){
        String regex = "(.{2})";
        String[] strArr = str.replaceAll(regex,"$1 ").split(" ");
        byte[] data = new byte[strArr.length];
        for (int i = 0; i < strArr.length; i++) {
            data[i] = (byte)Integer.parseInt(strArr[i], 16);
        }
        return data;
    }

    private void showData(ByteBuf buff){
        DataMapping mapping = unWrap(buff);
        switch (mapping.getType()) {
            case 0x02:
                ByteBuf buf = Unpooled.copiedBuffer(mapping.getData());
                String ymd = getYMD(buf);
                Map<String, Object> retMap = new HashMap<>();
                // 解析数据
                analysis(buf, retMap);
                printInfo(retMap);
                buf.release();
        }
    }

    public static class DataMapping {

        private byte type;
        private byte[] data;
        public byte getType() {
            return type;
        }

        public void setType(byte type) {
            this.type = type;
        }

        public byte[] getData() {
            return data;
        }

        public void setData(byte[] data) {
            this.data = data;
        }

    }

//    private static final String  str="";
private static final String  str1 ="232302fe4c47415833503133354c3630303034353301021b1603010a0a2d010201010000000040f61764248136020003ca000005000637cf8e01d6bba80601c8ffff01c8ffff010f3b010638070000000000000000000801011764248101680001c80cff0d010d020cff0d000cff0d040d000d000d000cfe0d000d020d020d000d010d000d030d000d000d010cff0cfe0cfc0cfd0cff0cff0d000d040cff0d010cff0cff0d030cff0cfe0cff0cfe0cff0cfe0cff0cff0cff0d000d000cff0cfe0cfd0d030d020d000cfe0cff0cff0d000d020d000cff0d000cfd0cfe0cff0d000d010d010d010d010cfe0d010d000cff0d000d000cff0cfe0cff0cff0cfe0cfd0cfd0cfe0cfe0cfd0cfc0cfe0cfd0cfd0cfe0cfe0cfd0cfe0d000cfe0cff0cfe0cfc0d000cff0d020d000cfe0cff0cfd0cfd0cfd0d000cfd0cfb0d000cff0cfe0cfd0cfd0cfe0cfe0cfd0cfe0cfc0cfc0cfe0d010cfd0cfe0d000cfd0cfd0cfd0cfe0cfe0d000cfd0cfe0d000d000d000d000d010cfe0cff0d000d000cfe0cfd0cfc0d010d000cff0cff0d000cff0d000cfe0d000cff0cfe0cfe0cfe0d000d000cfd0d000d000d030d020d010cfe0cfd0cfe0d010cff0cff0cfe0d000cff0cff0cff0d000cff0cfc0cfb0d040cff0d010cfe0cff0cff0cff0cfe0cff0cff0cfe0cfe0d010cfe0cfe0cfe0d000d010cff0cfe090101003c3939393939383939393939383a3a3b3a393a3a3a3a3a393a3a3a3b3a39393a3b3b3a393a3a3a3b3a393a3a3a3b3a393a3a3b3b3b393a3a3a3a3a393a74";
    private static final String str ="232302FE4C47415833503133354C3630303034353301021B1603090B0B0F01020101000000004C0E17D122504502000398000005000637CFF801D6BB600601310D4101C8FFFF010F4101013F0700000000000000000008010117D1225001680001C80D3E0D3F0D3E0D3D0D3D0D3C0D400D3D0D3D0D3E0D3B0D3C0D400D400D3E0D3E0D3D0D400D3E0D3D0D3E0D3B0D3B0D3A0D3B0D3B0D3C0D3E0D400D3C0D3C0D3C0D3C0D3C0D3B0D3A0D3E0D3C0D3E0D3C0D3D0D3C0D3B0D3D0D3B0D3D0D3C0D3D0D410D400D3C0D3C0D3D0D3E0D3E0D3F0D3D0D3C0D3B0D3A0D3B0D3C0D3D0D400D3F0D410D3E0D3A0D410D3E0D3D0D3D0D3E0D3D0D3C0D3B0D3B0D3B0D3A0D3A0D3C0D3D0D3A0D3A0D3D0D3B0D3A0D3A0D3A0D390D3B0D3D0D3B0D3C0D3A0D3A0D3D0D3C0D3F0D3D0D3B0D3C0D3B0D3A0D3B0D3D0D3A0D380D3E0D3B0D3B0D3A0D3A0D3A0D3B0D3A0D3B0D3A0D370D3A0D3C0D380D3A0D3A0D390D3A0D3A0D390D3C0D3B0D3C0D3B0D3D0D3C0D3B0D3B0D3E0D390D3C0D3C0D3C0D3B0D370D390D3D0D3D0D3D0D3D0D3E0D3C0D3A0D3B0D3D0D3D0D390D3C0D3D0D3B0D3A0D390D3D0D3C0D3";

    public static void main(String[] args) {
        TestMain test = new TestMain();
        ByteBuf buff = Unpooled.copiedBuffer(test.getData());
        test.showData(buff);
        buff.release();
    }
}
